package p12nrt;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.*;
import org.apache.lucene.search.highlight.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.apache.tika.Tika;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executors;

/**
 *根据业务场景判断是否要进行实时搜索或者近实时搜索
 * 1，完全实时搜索：只要数据库一变动，马上跟新索引，通过writer.commit()进行提交（代价，效率低）
 *
 * 2，近实时搜索 :当用户修改了信息之后，先把索引保存到内存种，然后一个统一的时间内，对内存种的所有
 *索引，进行提交操作（通过writer来打开索引文件？）（这种情况需要解决一个问题就是并发问题，假如有两个
 * 用户修改了数据，在提交之前都保存在内存种，会造成数据不一致）
 * lucen3.5后，提供了NRTmanager(near-real-time)
 * 和searchManager 来管理这种近实时搜索
 *
 *
 */
public class IndexUitls12 {
    private SearcherManager searcherManager;
    private NRTManager nrtManager;//通过nrtManager 获取searchManager();
    private IndexWriter indexWriter;

    //1,通过 searchManager 来获取search
    /*public IndexUitls12() {
        try {
            Directory directory=FSDirectory.open(new File("d:/lucene/index12"));
            this.searcherManager =new SearcherManager(directory, new SearcherWarmer() {
                @Override
                public void warm(IndexSearcher s) throws IOException {
                    //当 searcherManager.maybeReopen() 调用的时候，会执行这个方法，
                    // （比如可以在这个方法种进行一些资源控制）
                    System.out.println("has change-------->");
                }
            }, Executors.newCachedThreadPool());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }*/

    //2,通过 NRTManager 来获取 search

    public IndexUitls12() {
        try {
            Directory directory=FSDirectory.open(new File("d:/lucene/index12"));
            IndexWriterConfig config=new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35));
            indexWriter=new IndexWriter(directory,config);
            //在添加 文档，跟新，删除，都可以用这个nrtManager 了，他提供了writer的所有方法
            nrtManager=new NRTManager(indexWriter, new SearcherWarmer() {
                @Override
                public void warm(IndexSearcher s) throws IOException {
                    System.out.println("has change 2");
                }
            });
            //后台线程，设置多长时间启动一次
            //一般建议最大的时间5.0，最小的时间0.025（表示25秒，打开一次）
            NRTManagerReopenThread thread=new NRTManagerReopenThread(nrtManager,5.0,0.025);
            thread.setDaemon(true);//设置为后台守护线程
            thread.setName("this is thread");
            thread.run();
            //true 表示允许所有更新
            searcherManager=nrtManager.getSearcherManager(true);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void search1(){
        //这里通过 searchManager 的accquire 方法来获取search
        IndexSearcher searcher=searcherManager.acquire();
        try{
            //加这个的方法的目的是用来判断，是否需求重新打开索引文件，比如在多线程种，如果，一个线程删除了某个
            //索引项，另一个线程去查的时候，如果不重新打开索引文件的话，这种变化当前打开的索引文件就感知不到
            //这种变化，所以需要重新打开下索引项，但是这个方法不是随时用的，在接近实时搜索的需求下，一般是
            //隔一定的时间打开一下，注意，此种搜索，一定跟新的时候，writer.commit()，一定要提交，如果不提交的
            //话，也没办法感知到，，其他线程的跟新操作，这个只是提交之后才能感知到变化，
            searcherManager.maybeReopen();
        }catch (Exception e){

        }finally {
            //这里就不通过 search.close()来关闭了，而是通过下面的方法
            try {
                searcherManager.release(searcher);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
